home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / c_hints.exe / HINTS.DOC < prev   
Text File  |  1992-07-12  |  32KB  |  759 lines

  1.  
  2.         HINTS FOR EFFICIENT PROGRAMMING
  3.         Copyright (c) 1992 by Omega Point, Inc.
  4.            Author: Ratko V. Tomic
  5.  
  6.  
  7. -------------------------------------------------------------------------
  8. NOTE: The text below is taken from the CodeRunneR (R) manual. CodeRunneR
  9.       is a TSR library for C and assembly programmers, thus many hints
  10.       deal implicitly with size optimization. For more information about
  11.       CodeRunneR call Omega Point (508) 877-1819 or fax (508) 877-0915.
  12. -------------------------------------------------------------------------
  13.  
  14. CodeRunneR was designed with the greatest attention for efficiency (size
  15. and speed), all functions were carefully crafted in assembly language.
  16. Combined with some care in the C code you can produce programs rivaling
  17. in size to average assembly language programs, especially on medium and
  18. large projects. On very small programs (few hundred bytes), the assembly
  19. language will still be ahead. In terms of speed, the video functions
  20. (at least) should be competitive with pure assembly code.
  21.  
  22. The C programming hints below have been found useful in reducing the
  23. efficiency gap between C and assembly code.
  24.  
  25. 1. INT or CHAR - Current compilers are notoriously bad in handling 
  26.    expressions involving byte size data. The reason for this is an
  27.    overly literal interpretation of C "abstract machine", which mandates
  28.    that the result should be evaluated as if extended to integer. On the
  29.    other hand, the xxx86 processors have a rich subset of instructions
  30.    operating on byte size items. These instructions make great majority
  31.    of "integral promotions" unnecessary. Unfortunately, only a small
  32.    fraction of these are utilized by C compilers, resulting in much more
  33.    expensive operations on char versus int variables. Thus a saving of
  34.    one byte for the variable storage is practically always more than 
  35.    paid for in code size.
  36.    
  37.    The following rules have been found useful in reducing this type 
  38.    of inefficiency:
  39.  
  40.    a) If a char variable is used within expressions, or is being passed to
  41.       functions, or returned by functions, it is better to use int instead.
  42.       This is true even in case when variable is only used as TRUE/FALSE
  43.       flag. If defined as an int, the variable will occupy 1 more byte,
  44.       but for each use one or more bytes are saved in generated code.
  45.       In addition the speed is often improved due to an even address
  46.       alignment of variables, preferred by the 16/32 bit CPU-s.
  47.  
  48.    b) In some situation rule (a) cannot be applied, since an array of
  49.       characters is the source for byte size variables. In that case
  50.       the characters should be cast as SIGNED whenever possible since
  51.       the instruction CBW used to extend signed char to int is 1 byte,
  52.       while the instruction MOV AH,0 used for unsigned is 2 bytes.
  53.  
  54.    c) CodeRunner functions which receive char or byte as an argument
  55.       will ignore high byte passed. Hence you can safely pass integers
  56.       without having to mask out high byte. This also allows application
  57.       of the rule (b) independently of char being below or above 0x80.
  58.  
  59.    d) Auto variables of char type will occupy two bytes on stack
  60.       anyways, hence one should always gain by using int instead.
  61.  
  62.    e) If an integer variable is to be compared to a char, or passed to
  63.       function expecting char, casting integer to char is better than
  64.       AND-ing it with 0xff.
  65.  
  66.  
  67. 2. INITIALIZED AUTO variables for strings, arrays, structures or any
  68.    composite objects are very inefficient. Each such object will
  69.    occupy exactly twice the size defined. Also, the compiler will
  70.    on every function entry call an internal transfer function to
  71.    copy the variable from original place into the auto variable.
  72.    Besides wasting time, this transfer function is not usable by
  73.    the C code as a memory copy function. And lastly, the space
  74.    used as the destination is also internal space (stack space),
  75.    which will often place much heavier demand on stack size. You
  76.    can often create a "local copy" of such item in some temporarily
  77.    free buffer (e.g. a disk i/o buffer when disk i/o is idle).
  78.  
  79.    a) If this type of variables is truly needed (rare case), one may
  80.       use other general purpose memory copy function (like memcpy())
  81.       which is usable for other purposes as well. In case of Turbo C
  82.       this is even more important, since Turbo C uses far call and
  83.       32 bit pointers to perform the copying, even in small model.
  84.  
  85.    b) In most situations, the intention was only to keep a variable
  86.       local to the function and not to reinitialize variable each time
  87.       function is activated. In that case the variable should be turned
  88.       into static, accomplishing same result in half the size.
  89.  
  90.       Hence instead of:
  91.  
  92.         func() 
  93.         { 
  94.         char msg[]="This is an initialized local string.";
  95.         }
  96.  
  97.       it is better to use:
  98.  
  99.         func()
  100.         {
  101.         static char msg[]="This is an initialized local string.";
  102.         }
  103.  
  104.      This is one example where ANSI C standard has violated a useful
  105.      classic C rule that more efficient constructs are shorter to type.
  106.  
  107.  
  108. 3. Another case of the same Classic C rule violation is the passing of
  109.    structures by value to/from functions. Such deceivingly efficient
  110.    constructs are wasteful on memory and time even when implemented
  111.    well, and especially in the current C compilers where they were added
  112.    as a marketing feature to boost the count of ANSI compliance points.
  113.  
  114.    Hence instead of:
  115.  
  116.      struct x_type func(struct x_type x)
  117.      {
  118.        ....
  119.        process(x.field);
  120.        ....
  121.        return(x);
  122.        ....
  123.      }
  124.  
  125.    it is more efficient to use:
  126.  
  127.      void funct(struct x_type *x)
  128.      {
  129.        ...
  130.        process(x->field);
  131.        ...
  132.        return;
  133.       }
  134.  
  135.    In rare circumstances, where a local copy of a structure is needed in
  136.    order to be modified while preserving the callers copy, it is still
  137.    better to use a general purpose memory copy, rather than have compiler
  138.    link in an internal-use-only transfer function.
  139.  
  140. 4. Uninitialized AUTO variables are more efficient than the equivalent
  141.    static/global variables both in memory (typically 1 byte per access)
  142.    and speed. Additionally, the space used by auto variables is released
  143.    when function exits. Therefore both simple and composite objects
  144.    needed temporarily and locally should be defined as auto variables.
  145.  
  146.    Similar situation is with arguments a function receives - they are
  147.    equivalent to auto variables in efficiency, thus they are often 
  148.    better than global variables.
  149.  
  150. 5. Variables which are OFTEN being passed as arguments between functions
  151.    should be redefined as globals, ar at least static for that module.
  152.    This rule needs to be counterbalanced with the previous rule - the
  153.    decision parameter is "often". Namely each access to a global/static
  154.    costs on average 1 extra byte (compared to access of a function
  155.    argument), but the cost of passing such variable is on average 5 bytes.
  156.    
  157. 6. If a variable occurs in the code as say: n-1, two or more times, it
  158.    is better to define another variable, n1=n-1 and use n1 instead.
  159.    Just the code space saved on the single re-use pays for the
  160.    extra space of variable n1. The program speed will benefit too.
  161.    This rule is applicable to char, int, long variables as well as
  162.    pointers to any objects. More complex expressions (than n-1)
  163.    will benefit even more.
  164.  
  165.    Note also that the assignement (n1=n-1; above) should be combined
  166.    with the first use of (n-1):
  167.  
  168.    For example instead of:
  169.  
  170.      y = f(x) + n - 1;
  171.      z = v * (n-1);
  172.  
  173.    use:
  174.  
  175.      y = f(x) + (n1=n-1);
  176.      z = v * n1;
  177.  
  178.  
  179. 7. 2-D arrays are not efficiently handled by C compilers. Each access
  180.    will produce multiply instruction to compute an offset into the array.
  181.    If a 2-D array is used mostly in a sequential manner (like screens,
  182.    edit buffers, matrices, etc.) one should define them as 1-D arrays
  183.    and compute starting offset expli